---
title: Simple Crowdfund
slug: /how-to-guides/v3/pallet-design/crowdfund
keywords: pallet design, intermediate, runtime, child trie
version: '3.0'
section: how to guides
category: pallet design
---

<Message
  type={`gray`}
  title={`Note`}
  text={`This guide assumes that developers know how to 
  create their own 'Errors' and 'Events' according to the 
  pallet logic they're creating.`}
/>

<Objectives
  data={[
    {
      title: 'Goal',
      description:
        'Build a pallet that controls multiple token accounts, storing data in child storage.',
    },
    {
      title: 'Use Cases',
      description: `A simple on-chain crowdfunding app for participants to pool funds towards a common goal.`,
    },
    {
      title: 'Overview',
      description: `Using a child trie provides two advantages over using standard storage. First, it allows for
        removing the entirety of the trie is a single storage write when the fund is dispensed or
        dissolved. Second, it allows any contributor to prove that they contributed using a Merkle Proof.
        This guide demonstrates how to use one trie for each active crowdfund. Any user can start a crowdfund by
        specifying a goal amount for the crowdfund, an end time, and a beneficiary who will
        receive the pooled funds if the goal is reached by the end time. If the fund is not successful, it enters into a
        retirement period when contributors can reclaim their pledged funds. Finally, an unsuccessful fund can be dissolved,
        sending any remaining tokens to the user who dissolves it.`,
    },
  ]}
/>

<Message
  type={`yellow`}
  title={`Information`}
  text={`To follow this guide and implement the crowdfunding capabilities in your own pallet,
        include the following dependencies in your pallet:
            
        use frame_support::{pallet_prelude::*, ensure, storage::child,
        traits::{Currency, ExistenceRequirement, Get, ReservableCurrency, WithdrawReasons},
        sp_runtime::{traits::{AccountIdConversion, Saturating, Zero, Hash},
        ModuleId}
        };
        use frame_system::{pallet_prelude::*, ensure_signed};
        use super::*;
  `}
/>

## Steps

### 1. Declaring your pallet's configuration traits

In addition to the ubiquitous `Event` type, this pallet will need:

- **`Currency`**. The currency in which the crowdfunds will be denominated.
- **`SubmissionDeposit`**. The amount to be held on deposit by the owner of a crowdfund.
- **`MinContribution`**. The minimum amount that may be contributed into a crowdfund.
- **`RetirementPeriod`**. The period of time in blocks during which contributors are able to
  withdraw their funds after an unsuccessful crowdfund ending.

```rust
/// The pallet's configuration trait.
#[pallet::config]
pub trait Config: frame_system::Config {
  type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
	type Currency: ReservableCurrency<Self::AccountId>;
	type SubmissionDeposit: Get<BalanceOf<Self>>;
	type MinContribution: Get<BalanceOf<Self>>;
	type RetirementPeriod: Get<Self::BlockNumber>;
}
```

### 2. Create a custom metadata struct

Keep track of the constants in your pallet by creating a struct that stores metadata about each fund:

```rust
#[derive(Encode, Decode, Default, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct FundInfo<AccountId, Balance, BlockNumber> {
    /// The account that will recieve the funds if the campaign is successful.
    beneficiary: AccountId,
    /// The amount of deposit placed.
    deposit: Balance,
    /// The total amount raised.
    raised: Balance,
    /// Block number after which funding must have succeeded.
    end: BlockNumber,
    /// Upper bound on `raised`.
    goal: Balance,
}
```

### 3. Declare your storage items

Our storage items will need to keep track of which user contributed to what fund as well as how much they contributed. First, define the following types which will be used to declare our storage items:

```rust
pub type FundIndex = u32;
type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
type BalanceOf<T> = <<T as Config>::Currency as Currency<AccountIdOf<T>>>::Balance;
type FundInfoOf<T> = FundInfo<AccountIdOf<T>, BalanceOf<T>, <T as frame_system::Config>::BlockNumber>;
```

Now, use those types to create one `StorageMap` item that tracks the funds by index and a second, `StorageValue`, that keeps track of `FundIndex`:

```rust
#[pallet::storage]
#[pallet::getter(fn funds)]
/// Info on all of the funds.
pub(super) type Funds<T: Config> = StorageMap<
  _,
  Blake2_128Concat,
  FundIndex,
  FundInfoOf<T>,
  OptionQuery,
>;

	#[pallet::storage]
	#[pallet::getter(fn fund_count)]
	/// The total number of funds that have so far been allocated.
	pub(super) type FundCount<T: Config> = StorageValue<_, FundIndex, ValueQuery>;
```

### 4. Write child trie API helper functions

First, we'll need to create a function that provides the pallet's dispatchables with the account ID for the pot of funds. Inside `impl<T: Config> Pallet<T>`, write:

```rust
const PALLET_ID: ModuleId = ModuleId(*b"ex/cfund");
/**snip**/
pub fn fund_account_id(index: FundIndex) -> T::AccountId {
    PALLET_ID.into_sub_account(index)
	}
```

Then, we'll need to generate unique [ChildInfo][childinfo-rustdocs] IDs:

```rust
pub fn id_from_index(index: FundIndex) -> child::ChildInfo {
  let mut buf = Vec::new();
  buf.extend_from_slice(b"crowdfnd");
  buf.extend_from_slice(&index.to_le_bytes()[..]);

  child::ChildInfo::new_default(T::Hashing::hash(&buf[..]).as_ref())
}
```

Finally, we can write the following helper functions that make use of the [Child API][child-api-rustdocs]:

- **`pub fn contribution_put`**: record a contribution in the associated child trie using [`put`][child-api-put-rustdocs]

- **`pub fn contribution_get`**: lookup a contribution in the associated child trie using [`get`][child-api-get-rustdocs]

- **`pub fn contribution_kil`**: remove a contribution from an associated child trie using [`kill`][child-api-kill-rustdocs]

- **`pub fn crowdfund_kill`**: remove the entire record of contributions in the associated child trie in a single storage write using [`kill_storage`][child-api-killstorage-rustdocs]

### 5. Write your dispatchable functions

The follow steps outline how to write the dispatchables for this pallet. After various checks within the dispatchables' logic, each function alters the `Funds<T>` storage map using
its [associated methods][storage-map-rustdocs]. Our pallet's `create` function also makes use of the `FundInfo` struct created in [step 2](#2-create-a-custom-metadata-struct).

#### Create a new fund

`fn create`:

- create an imbalance variable using [`T::Currency::withdraw`][imb-var-rustdocs]
- update the `Funds` storage item using the `FundInfo` struct from [step 2](#2-create-a-custom-metadata-struct)
- deposit a `Created` event

<Message
  type={`green`}
  title={`Tip`}
  text={`
Not yet familiar with using a struct in storage? Refer to [this how-to guide](../storage-value) to
learn how.
  `}
/>

#### Contribute funds to an existing fund

`fn contribute`:

- perform preliminary safety checks using `ensure!`
- add the contribution to the fund using `T::Currency::transfer`
- record the contribution in the child trie using the helper function `contribution_put`
- deposit a `Contributed` event

#### Withdraw full balance of a contributor to a fund

`fn withdraw`:

- perform preliminary safety checks using `ensure!`
- return funds by using [`T::Currency::resolve_into_existing`][resolve-into-existing-rustdocs]
- calculate new balances and update storage using child trie helper functions `funds`, `contribution_get` and `contribution_kill`
- deposit `Withdrew` event

#### Dissolve an entire crowdfund after its retirement period has expired.

`fn dissolve`:

- perform preliminary safety checks using `ensure!`
- allow dissolver to collect funds by using [`T::Currency::resolve_creating`][resolve-creating-rustdocs] for dissolver to collect funds
- use the child trie helper function `crowdfund_kill` to remove contributor info from storage
- deposit `Dissolved` event

#### Dispense a payment to the beneficiary of a successful crowdfund

`fn dispense`:

- use [`T::Currency::resolve_creating`][resolve-creating-rustdocs] for beneficiary and caller (separately) to collect funds
- give initial deposit to account who calls this function as an incentive to clean up storage
- remove the fund from storage using `<Funds<T>>::remove(index);` and `Self::crowdfund_kill(index);` to remove all contributors from storage in a single write

## Examples

- [`pallet_simple_crowdfund`](https://github.com/substrate-developer-hub/substrate-how-to-guides/blob/main/example-code/template-node/pallets/simple-crowdfund/src/lib.rs#L1)

## Resources

#### Rust docs

- [Currency Imbalance trait](/rustdocs/latest/frame_support/traits/trait.Imbalance.html)
- [Child trie API][child-api-rustdocs]
- [`extend_from_slice`](/rustdocs/latest/frame_support/dispatch/struct.Vec.html#method.extend_from_slice)
- [`using_encode`](/rustdocs/latest/frame_support/pallet_prelude/trait.Encode.html#method.using_encoded)

[storage-value-struct-htg]: /storage-value-struct
[storage-map-rustdocs]: /rustdocs/latest/frame_support/pallet_prelude/struct.StorageMap.html
[imb-var-rustdocs]: /rustdocs/latest/frame_support/traits/trait.Currency.html#tymethod.withdraw
[resolve-into-existing-rustdocs]: /rustdocs/latest/frame_support/traits/trait.Currency.html#method.resolve_into_existing
[resolve-creating-rustdocs]: /rustdocs/latest/frame_support/traits/tokens/currency/trait.Currency.html#method.resolve_creating
[childinfo-rustdocs]: /rustdocs/latest/frame_support/storage/child/enum.ChildInfo.html
[child-api-rustdocs]: /rustdocs/latest/frame_support/storage/child/index.html#functions
[child-api-put-rustdocs]: /rustdocs/latest/frame_support/storage/child/fn.put.html
[child-api-get-rustdocs]: /rustdocs/latest/frame_support/storage/child/fn.get_or_default.html
[child-api-kill-rustdocs]: /rustdocs/latest/frame_support/storage/child/fn.kill.html
[child-api-killstorage-rustdocs]: /rustdocs/latest/frame_support/storage/child/fn.kill_storage.html
